%-----------------------------------------------------------------------------
\chapter{Umsetzung}
%-----------------------------------------------------------------------------
Dieses Kapitel beschäftigt sich mit den Anforderungen, die eine Struktur
erfüllen muss, um auf gespeicherte Code Snippets mittels Volltextsuche
zugreifen zu können, beschreibt die gewählte Struktur und mögliche
Alternativen dazu. Davor werden noch die Rahmenbedingungen geklärt, die für alle
Strukturen gleich sind.  


%-----------------------------------------------------------------------------
\section{Anforderungen an die Datenstruktur}
%-----------------------------------------------------------------------------
Die Struktur, in der die Code Snippet Collection die Daten speichert, muss
folgende Anforderungen erfüllen:
\begin{itemize}
	\item Schnelligkeit
	\item Datensicherheit
	\item Volltextsuche über Titel, Beschreibung und Source Code 
	\item Suchen nach bestimmten Attributen, im konkreten Fall sind das
	Programmiersprache und Tags.
\end{itemize}

In der Struktur müssen folgende Daten zu jedem Code Snippet gespeichert werden:
\begin{itemize}
	\item Titel
	\item Beschreibung
	\item Programmiersprachen
	\item Tags
	\item Git-Filename samt Pfadangabe
\end{itemize}


%-----------------------------------------------------------------------------
\section{Rahmenbedingungen}
%-----------------------------------------------------------------------------
Im Prototypen der Code Snippet Collection von Bregenzer ist die
Authentifizierung für den Zugriff über ein eigenes Authentifizierungsschema
realisiert und hinterlegt die Daten in einer relationalen Datenbank. In der idealen
Architektur würde die Authentifizierung über einen FH-Joanneum-LDAP-Server
realisiert werden \cite{Breg11}. Da die Authentifizierung nicht Teil dieser
Arbeit ist, ist sie für die Auswahl der Struktur nicht relevant.
\newline
\newline
Die Versionierung der Code Snippets bleibt im Prototypen auch unverändert. Git
ist die modernere Versionskontrolle und wird auch auf Grund der Vorteile
gegenüber zentraler Versionskontrollen weiter verwendet.
\newline
\newline
Durch die Beibehaltung der Authentifizierung und der Versionierung für den
Source Code spielt die Datensicherheit für die Auswahl der Speicherstruktur nur
mehr eine untergeordnete Rolle, weil sie für alle gleich bleibt.

%-----------------------------------------------------------------------------
\section{Such-Server}
%-----------------------------------------------------------------------------
Als Such-Server wurde Solr gewählt, weil dieser die Möglichkeit bietet, den
Suchraum vor der Indizierung individuell aufzubereiten. Dadurch wird der Index
so klein wie möglich gehalten und in weiterer Folge eine performante Suche
erreicht. Dieser Punkt ist vor allem bei einer Code Snippet Collection relevant,
weil Source Code bei der Indizierung sehr speziell zu behandeln ist.
\newline
\newline
Für die Interaktion mit dem Solr-Server wurde Sunspot verwendet, weil
Sunspot in Kombination mit Ruby on Rails eine einfache und intuitive Möglichkeit
darstellt, den Solr-Server zu bedienen.
\newline
\newline
Elasticsearch ist eine Alternative zu Sunspot, hat seine Vorteile bei
Cloud- oder verteilten Anwendungen. Da dies aber keine Anforderungen an den
Prototypen sind, wurde Sunspot für die Implementierung verwendet.

%-----------------------------------------------------------------------------
\subsection{Suchraum Aufbereitung}
%-----------------------------------------------------------------------------
Eine hohe Performance bei einer Volltextsuche setzt einen gut gewählten Index
voraus. Wenn man sich die zu speichernden Daten eines Code Snippets unter dem
Aspekt einer Aufbereitung des Suchraumes für eine Indizierung ansieht, kann man die
Daten in drei Gruppen einteilen, die jeweils eine unterschiedliche Aufbereitung
benötigen.


%-----------------------------------------------------------------------------
\subsubsection{Aufbereitung von Programmiersprache und Tag}
%-----------------------------------------------------------------------------
Die Programmiersprache und der Tag benötigen keine Aufbereitung, weil sie nur
als zusätzliche Einschränkung dienen und von der Webapplikation fix 
bzw. sehr einheitlich vergeben werden.

%-----------------------------------------------------------------------------
\subsubsection{Aufbereitung von Titel und Beschreibung}
%-----------------------------------------------------------------------------
ProgrammierInnen stehen manchmal vor der Entscheidung, ob sie Kommentare,
Funktionsnamen etc. in deutscher oder in englischer Sprache schreiben sollen.
Daher ist es bei der Suchraumaufbereitung von Titel und Beschreibung neben der
konventionellen Aufbereitung wie Stemming auch eine individuelle Lemmatization
notwendig, damit deutsche und englische IT-Fachbegriffe aufeinander gemapt
werden.


%-----------------------------------------------------------------------------
\subsubsection{Aufbereitung des Quellcodes}
%-----------------------------------------------------------------------------
Gerade bei Quellcode gibt es pro Programmiersprache bedingt durch die
Syntax viele Wörter, die für die Suche nicht relevant sind. Durch eine
entsprechende Stoppwortliste kann trotzdem der Index klein gehalten werden. Bei
den zusätzlich im Quellcode enthaltenen Kommentaren hat man das gleiche Problem
wie bei Titel und Beschreibung, daher ist hier nach dem Stemming eine entsprechende Lemmatization
notwendig.

%-----------------------------------------------------------------------------
\section{Alternative Such-Server}
%-----------------------------------------------------------------------------
Alternativen zum gewählten Suchserver sind Apache Solr und Apache Lucene, wobei
Solr auf Lucene aufbaut. Durch die Verwendung von Sunspot erspart man sich die
Erstellung von Funktionalitäten, die von Sunspot zur Verfügung gestellt
werden.
\newline
\newline
Eine weitere Alternative ist Elasticsearch, das Produkt ist aber hauptsächlich
für verteilte Systeme konzipiert worden und daher bekam Sunspot den Vorzug.

%-----------------------------------------------------------------------------
\section{Gewählte Struktur}
%-----------------------------------------------------------------------------
Im Git wird ein Repository und darunter pro Programmiersprache je ein
Ordner angelegt. Wird ein Code Snippet über die Applikation gespeichert,
erfolgt die Speicherung direkt im entsprechenden Repository mit dem/der
angemeldeten BenutzerIn als Autor/In.
Titel, Beschreibung, Git-Filename samt Pfadangabe, Programmiersprache und
zugeordnete Tags werden wie bisher in einer relationalen Datenbank gespeichert.
Titel, Beschreibung, Programmiersprache und vergebenen Tags werden
indiziert, um eine Volltextsuche zur Verfügung stellen zu können.
\newline
\newline
Wird ein Code Snippet bei der Neuanlage oder auch bei einer Änderung
gespeichert, wird der neue oder geänderte Source Code im Git eingecheckt.
Zusätzlich wird auch der Index angepasst.
\newline
\newline
Bei der Suche nach einem Code Snippet erfolgt über den Solr-Server
eine Volltextsuche über den Index des Solr-Servers. 
\newline
\newline
Während Git in der gewählten Struktur die geforderte Datensicherheit garantiert,
deckt man durch die Verwendung von Solr als Such-Server folgende
Anforderungen ab:
\begin{itemize}
	\item Schnelligkeit
	\item Volltextsuche über Titel, Beschreibung und Source Code 
	\item Möglichkeit der Suche nach bestimmten Attributen, im konkreten Fall sind
	das Programmiersprachen und Tags.
\end{itemize}




%-----------------------------------------------------------------------------
\section{Alternative Strukturen}
%-----------------------------------------------------------------------------
Alternativ zu der gewählten Struktur, könnte man zur Speicherung der Daten
eine relationale Datenbank verwenden, die auch eine Volltextsuche anbietet. 
Diese Datenbanken bieten aber keine Aufbereitung des Suchraumes an, was aber
gerade bei einer Volltextsuche großen Einfluss auf die Performance der Suche
hat.
\newline
\newline
Die Programmiersprachen und Tags könnten auch direkt in den Source Code
geschrieben werden (z.B. als Kommentar). Dies hat den Nachteil, dass
diese Einträge beim Kopieren des Codes auch mitkopiert werden würden und man
sie aus dem eigentlichen Sourcecode wieder löschen müsste.


%-----------------------------------------------------------------------------
\section{Ergebnisse der Umsetzung}
%-----------------------------------------------------------------------------
Nach der Auswahl von Datenstruktur und Such-Server sind beide in die
bestehende Applikation zu integrieren. Dabei wird sowohl die Systemarchitektur
also auch die Code Snippet Collection selbst geändert. Ein weiterer Punkt
ist auch die Installation Sunspot und die Konfiguration des Suchervers. Durch
die Umsetzung der gewählten Struktur ergeben sich folgende Zwischenschritte und
Endergebnisse.


%-----------------------------------------------------------------------------
\subsection{Systemarchitektur}
%-----------------------------------------------------------------------------
Die Systemarchitektur der Code Snippet Collection wurde durch die
Implementierung der neuen Struktur um einen Apache Solr Server erweitert
(siehe Abb. ~\ref{Systemarchitektur} - Systemarchitektur der Code Snippet
Collection), wobei in der relationalen Datenbank Titel, Beschreibung,
Git-Filename samt Pfadangabe, Programmiersprache und zugeordnete Tags
gespeichert werden.
\newline
\newline
Der Solr-Server hält den Index und wird für die Volltextsuche verwendet.
\newline
\newline
Git speichert die Code-Snippets und stellt die Versionierung des Sourcecodes zu
Verfügung.

\begin{figure}[htbp]
    \centering
    \includegraphics [width=16cm,angle=0] {figures/csc_architecture.png}
    \caption{Systemarchitektur der Code Snippet Collection}
    \label{Systemarchitektur}
\end{figure}

%-----------------------------------------------------------------------------
\subsection{Verwendete Software Komponenten}
%-----------------------------------------------------------------------------
Die im Prototypen verwendeten Software Komponenten wurden übernommen bzw.
teilweise durch aktuellere Versionen ersetzt (genaue Auflistung siehe Anhang A).

Zusätzlich wurde noch Sunspot in der Version 2.0.0 verwendet. Bei der
Installation von Sunspot werden sämtliche Komponenten, die Sunspot benötigt,
automatisch mitinstalliert.

%-----------------------------------------------------------------------------
\subsection{Installation}
%-----------------------------------------------------------------------------
Wenn der Gem-File des Rails-Projektes um 
\newline
\newline
   \lstinline|gem "sunspot_rails"|
\newline
\newline
erweitert wird, reicht anschließend ein Bundle-Aufruf aus, um Sunspot zu
installieren. Die Installation sämtlicher benötigten Komponenten von Apache Solr
und auch die Erstellung der Konfigurationsfiles erfolgt durch den Befehl:
\newline
\newline
   \lstinline|rails generate sunspot_rails:install|
\newline
\newline
Das Starten des Solr-Servers erfolgt mit dem Befehl:
\newline
\newline
   \lstinline|bundle exec rake sunspot:solr:run|
\newline
\newline
Ein Starten des Servers als war Dienst nicht möglich. Beim Starten des Servers
werden die restlichen Konfigurationsdateien angelegt (siehe Abb. ~\ref{konfig_solr}).
\begin{figure}[htbp]
    \centering
    \includegraphics [width=16cm,angle=0] {figures/konfig_solr.png}
    \caption{Konfigurationsdateien Solr-Server}
    \label{konfig_solr}
\end{figure}

 
%-----------------------------------------------------------------------------
\section{Implementierung}
%-----------------------------------------------------------------------------
Für die Implementierung der Volltextsuche wurden folgende Anpassungen
vorgenommen.

%-----------------------------------------------------------------------------
\subsection{Aufbereitung des Suchraumes}
%-----------------------------------------------------------------------------
Die Aufbereitung des Suchraumes wird in der Datei "`schema.xml"' (befindet
sich im Konfigurationsordner von Solr siehe Abb. ~\ref{konfig_solr}) festgelegt.
Die Standardinstallation von Sunspot verwendet weder Synonyme noch eine
Stoppwortliste, daher wurde die Datei für die Verwendung von Synonymen wie
folgt geändert:
\newline
\newline
\begin{lstlisting}[caption=Schema.xml - Synonyme]{Name}
    <fieldType name="text" class="solr.TextField" omitNorms="false">
		<analyzer type="query">
    		<tokenizer class="solr.StandardTokenizerFactory"/>
    		<filter class="solr.StandardFilterFactory"/>
    		<filter class="solr.LowerCaseFilterFactory"/>
  		</analyzer>
  		<analyzer type="index">
    		<tokenizer class="solr.StandardTokenizerFactory"/>
    		<filter class="solr.StandardFilterFactory"/>
    		<filter class="solr.LowerCaseFilterFactory"/>
    		<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true" />
  		</analyzer>
	</fieldType>
\end{lstlisting}

Es ist zu beachten, dass Synonyme nur bei der Indexierung verwendet werden
und nicht bei der Suchraumaufbereitung. Die Synonyme werden in der Datei
synonyms.txt gespeichert. Im konkreten Fall wurden gängige IT-Abkürzungen
eingetragen, z.B:
\newline
\newline
\begin{lstlisting}[caption=Synonyms.txt - Synonyme]{Name}
	api,application programmer interface,application programming interface
	esql, embeeded sql
	oop, objektorientiertes programmieren, objectoriented programming,
	object-oriented programming
\end{lstlisting}

Die Stoppwörter sind in der Datei "`stopwords.txt"' hinterlegt. Damit die Liste
berücksichtigt wird, erfolgt folgende Ergänzung in der Datei "`schema.xml"':
\newline
\newline
\begin{lstlisting}[caption=Schema.xml - Stoppwörter]{Name}
<fieldtype name="teststop" class="solr.TextField">
   <analyzer>
     <tokenizer class="solr.LowerCaseTokenizerFactory"/>
     <filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/>
   </analyzer>
</fieldtype>
\end{lstlisting}
 
Nach Änderungen der Datei "`schema.xml"' muss Sunspot den Index neu aufbauen, was mit
\newline
\newline
\lstinline|rake sunspot:reindex|
\newline
\newline
erfolgt. Je nach Umfang der indizierten Daten kann das eine Weile in Anspruch
nehmen. 

%-----------------------------------------------------------------------------
\subsection{Indexierung und Indizieren}
%-----------------------------------------------------------------------------
Der nächste Schritt nach der Konfiguration der Aufbereitung ist die
Indexierung der gewünschten Felder im entsprechenden Model. Im konkreten Fall
sind das: der Titel, die Beschreibung, Source Code und die dem Code Snippets
zugeordneten Programmiersprachen und Tags. Wobei die Programmiersprachen und die Tags als
"`facet"' zu definieren sind, um danach filtern zu können. Das Ranking des
Suchergebnisses, welches Sunspot liefert, wurde angepasst:
Wird der Suchtext im Titel des Code Snippets gefunden, ist dies fünfmal
relevanter, als wenn der Suchtext nur in der Beschreibung gefunden wird.
\newline
\newline
Die Volltextsuche über den Sourcecode erwies sich als nicht zielführend,
weil dadurch die Ergebnisse zu ungenau wurden. Daher wurde der Index für den
Sourcecode aus dem Prototypen genommen.
\newline
\begin{lstlisting}[caption=Indexierung]{Name}
     searchable do
        text :name, 
        	 :stored => true, 
        	 :boost => 5 
        text :desc, 
        	 :stored => true  
        text :lang_list, 
        	 :stored => true, 
        	 :multiple => true  
        text :tag_list,
             :stored => true, 
        	 :multiple => true
     end
\end{lstlisting}

Die Anpassung des Indexes bei Neuerstellung, Änderungen und auch beim Löschen
eines Code Snippets erfolgt durch Sunspot selbstständig.

%-----------------------------------------------------------------------------
\subsection{Implementierung der Volltextsuche}
%-----------------------------------------------------------------------------
Für die Anzeige des Suchergebnisses ist noch der entsprechende Controller zu
ändern:
\newline
\begin{lstlisting}[caption=Anpassung Controller]{Name}
     def index
     @search = Snippet.search do
         fulltext params[:search]
     end
     @snippets = @search.results
\end{lstlisting}

Das Suchfeld wurde auch entsprechend geändert.
\newline
\begin{lstlisting}[caption=Anpassung Suchfeld]{Name}
     <%= form_tag snippets_path, :method => 'get' do %>
         <%= text_field_tag :search, params[:search], 
         :placeholder => 'Search for CodeSnippets...', 
         :size => 50 %>
         <%= submit_tag "Search", :name => nil %>
     <% end %>
\end{lstlisting}


%-----------------------------------------------------------------------------
\subsection{Prototyp Layout}
%-----------------------------------------------------------------------------
Das Layout des bestehenden Prototyps wurde den Anforderungen an die ideale
Speicherstruktur angepasst (siehe Abb. ~\ref{Search}).
\newline
\newline
\begin{figure}[htbp]
    \centering
    \includegraphics [width=16cm,angle=0] {figures/search.png}
    \caption{Suche von Code Snippet}
    \label{Search}
\end{figure}

Die Auswahl der Programmiersprache erfolgt über eine Verknüpfung pro
Programmiersprache auf der rechten Seite, wobei pro Programmiersprache auch die
Anzahl der gefundenen Code Snippets angezeigt wird. Bei jeder Suche wird die
Anzahl aktualisiert. Gibt es zu einer Suche kein Code Snippets in der
entsprechenden Sprache, wird die Programmiersprache auch nicht mehr angezeigt.
Die Filterung des Suchergebnis nach einer Programmiersprache kann auch wieder
aufgehoben werden. Dieses Feature wurde wie folgt implementiert:
\newline
\begin{lstlisting}[caption=Filterung Programmiersprachen]{Name}
	@search.facet(:lang_list).rows.each_with_index do |facet, index|
    	break if index == 30;
    
    	# check if facet is selected
    	if (params[:lang].kind_of?(Array) and params[:lang].include? facet.value)
      		lang_facets = existing_lang_facets - [facet.value]      
      		facet_links_lang_on << "<li>#{link_to facet.value, :search => params[:search], :lang => lang_facets} (x)</li>"
    	elsif @hits.size > 0
      		lang_facets = existing_lang_facets + [facet.value]
      		facet_links_lang_off << "<li>#{link_to facet.value, :search => params[:search], :lang => lang_facets} (#{facet.count})</li>"
    	end
    end
\end{lstlisting}

Die zugeordneten Tags werden unterhalb des Blocks der Programmiersprachen
angezeigt und bieten die gleichen Filteroptionen wie die Programmiersprachen.


